using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;

namespace OpenWaves.ActivityFeed.Web
{
    public abstract class UpdateDtoBuilderBase<T> : IUpdateDtoBuilder where T : UpdateDto
    {
        private readonly IUserProfileProvider userProfileProvider;

        protected UpdateDtoBuilderBase(IUserProfileProvider userProfileProvider)
        {
            Contract.Requires<ArgumentNullException>(userProfileProvider != null);

            this.userProfileProvider = userProfileProvider;
        }

        protected abstract T CreateDto(Update update);

        protected virtual void MapUpdateToDto(Update update, T dto)
        {
            dto.Id = update.Id;
            dto.Publisher = UserDto.FromUserId(update.PublishedBy, userProfileProvider);
            dto.Source = update.Source;
            dto.PublishedOn = update.PublishedOn;
            dto.ContentType = StringUtils.ToCamelCase(update.Content.GetType().Name);
            dto.Content = update.Content;

            dto.Comments = update.Comments.Select(c => CommentDto.FromComment(c, userProfileProvider));
            dto.Likes = update.GetLikes().Select(l => LikeEntryDto.FromLike(l, userProfileProvider));
        }

        public virtual UpdateDto BuildUpdateDto(Update update)
        {
            var dto = this.CreateDto(update);
            this.MapUpdateToDto(update, dto);
            return dto;            
        }

        public virtual IEnumerable<UpdateDto> BuildUpdateDtos(IEnumerable<Update> updates)
        {
            return updates.Select(u =>
                                      {
                                          var dto = this.CreateDto(u);
                                          this.MapUpdateToDto(u, dto);
                                          return (UpdateDto)dto;
                                      });
        }
    }

    public class UpdateDtoBuilder : UpdateDtoBuilderBase<UpdateDto>
    {
        public UpdateDtoBuilder()
            : this(ServiceLocator.Resolve<IUserProfileProvider>())
        {
        }

        public UpdateDtoBuilder(IUserProfileProvider userProfileProvider) : base(userProfileProvider)
        {
        }

        protected override UpdateDto CreateDto(Update update)
        {
            return new UpdateDto();
        }
    }

    internal static class StringUtils
    {
        [SuppressMessage("Microsoft.Globalization", "CA1308:Normalize strings to uppercase")]
        public static string ToCamelCase(string s)
        {
            if (string.IsNullOrEmpty(s))
                return s;

            if (!char.IsUpper(s[0]))
                return s;

            if (s.Length > 1)
            {
                return char.ToLowerInvariant(s[0]) + s.Substring(1);
            }
            else
            {
                return s.ToLowerInvariant();
            }
        }
    }
}